package com.sunkyc.framework.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sunkyc.commons.contants.GlobContants;
import com.sunkyc.commons.entity.TablePageData;
import com.sunkyc.commons.enums.DataScopeType;
import com.sunkyc.commons.exception.CustomerException;
import com.sunkyc.framework.system.CacheKey.AuthroticationCacheKeys;
import com.sunkyc.framework.system.CacheKey.SystemCacheKeys;
import com.sunkyc.framework.system.entity.SysRole;
import com.sunkyc.framework.system.entity.SysRoleDept;
import com.sunkyc.framework.system.entity.SysRoleMenu;
import com.sunkyc.framework.system.entity.SysUserRole;
import com.sunkyc.framework.system.mapper.SysRoleMapper;
import com.sunkyc.framework.system.service.SysRoleDeptService;
import com.sunkyc.framework.system.service.SysRoleMenuService;
import com.sunkyc.framework.system.service.SysRoleService;
import com.sunkyc.framework.system.service.SysUserRoleService;
import com.sunkyc.framework.utils.TablePageDataBuilderUtil;
import com.sunkyc.commons.entity.PageQueryVo;
import com.sunkyc.framework.utils.RedisUtils;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * <p>
 * 角色信息表 服务实现类
 * </p>
 *
 * @author sunkyc
 * @since 2022-05-31
 */
@Service
@RequiredArgsConstructor
public class SysRoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRole> implements SysRoleService {
    private final SysRoleMapper baseMapper;
    private final SysRoleMenuService roleMenuService;
    private final SysRoleDeptService roleDeptService;
    private final SysUserRoleService userRoleService;

    private final RedisUtils redisUtils;


    @Override
    @Transactional
    public int addRole(SysRole sysRole) {
        if(GlobContants.SUPER_ADMIN_USER_AND_ROLE_ID.equals(sysRole.getRoleId())){
            throw new CustomerException("超级管理员无法被修改");
        }
        int count = baseMapper.insert(sysRole);
        if (count > 0) {
            Long roleId = sysRole.getRoleId();
            List<Long> perms = sysRole.getPerms();
            for (Long perm : perms) {
                roleMenuService.save(new SysRoleMenu().setRoleId(roleId).setMenuId(perm));
            }
            redisUtils.deleteByPrefix(SystemCacheKeys.ROLE_DATA);
            redisUtils.deleteByPrefix(AuthroticationCacheKeys.AUTH_DATA_SCOPE_USER_ID_LIST);
        }
        return count;
    }


    @Override
    @Transactional
    public int updateRole(SysRole sysRole) {
        if(GlobContants.SUPER_ADMIN_USER_AND_ROLE_ID.equals(sysRole.getRoleId())){
            throw new CustomerException("超级管理员无法被修改");
        }
        int count = baseMapper.updateById(sysRole);
        if (count > 0) {
            // 删除角色对应的菜单ID 重新插入对应数据
            roleMenuService.remove(Wrappers.lambdaQuery(SysRoleMenu.class).eq(SysRoleMenu::getRoleId, sysRole.getRoleId()));
            List<Long> perms = sysRole.getPerms();
            for (Long perm : perms) {
                roleMenuService.save(new SysRoleMenu().setRoleId(sysRole.getRoleId()).setMenuId(perm));
            }
            redisUtils.deleteByPrefix(SystemCacheKeys.ROLE_DATA);
            redisUtils.deleteByPrefix(AuthroticationCacheKeys.AUTH_DATA_SCOPE_USER_ID_LIST);
        }
        return count;
    }

    @Override
    public Boolean checkedRoleUsedByRoleId(Long roleId) {
        return userRoleService.count(Wrappers.lambdaQuery(SysUserRole.class).eq(SysUserRole::getRoleId,roleId))>0;
    }

    @Override
    @Transactional
    public int delByRoleids(Long[] ids) {
        int count = 0;
        for (Long id : ids) {
            if(GlobContants.SUPER_ADMIN_USER_AND_ROLE_ID.equals(id)){
                throw new CustomerException("超级管理员无法被删除");
            }
            count = baseMapper.deleteById(id);
            if(count>0){
                roleMenuService.remove(Wrappers.lambdaQuery(SysRoleMenu.class).eq(SysRoleMenu::getRoleId, id));
                // 此处要删除对应的部门列表
                roleDeptService.remove(Wrappers.lambdaQuery(SysRoleDept.class).eq(SysRoleDept::getRoleId,id));
            }
        }
        redisUtils.deleteByPrefix(SystemCacheKeys.ROLE_DATA);
        redisUtils.deleteByPrefix(AuthroticationCacheKeys.AUTH_DATA_SCOPE_USER_ID_LIST);
        return count;
    }

    @Override
    public SysRole queryById(Long roleId) {
        SysRole sysRole = baseMapper.selectById(roleId);
        if(ObjectUtils.isNotEmpty(sysRole)){
            setDeptIds(sysRole);
            setPerems(sysRole);
        }
        return sysRole;
    }

    @Override
    @Transactional
    public int updateRoleDataScope(SysRole sysRole) {
        if(GlobContants.SUPER_ADMIN_USER_AND_ROLE_ID.equals(sysRole.getRoleId())){
            throw new CustomerException("超级管理员无法被修改");
        }
        int count = baseMapper.updateById(sysRole);
        if (count > 0) {
            roleDeptService.remove(Wrappers.lambdaQuery(SysRoleDept.class).eq(SysRoleDept::getRoleId,sysRole.getRoleId()));
            if(DataScopeType.CUSTOM.getCode().equals(sysRole.getDataScope())){
                for (Long deptId : sysRole.getDeptIds()) {
                    roleDeptService.save(new SysRoleDept().setRoleId(sysRole.getRoleId()).setDeptId(deptId));
                }
            }
            redisUtils.deleteByPrefix(SystemCacheKeys.ROLE_DATA);
            redisUtils.deleteByPrefix(AuthroticationCacheKeys.AUTH_DATA_SCOPE_USER_ID_LIST);
        }
        return count;
    }

    @Override
    public List<SysRole> queryAll() {
        String key = SystemCacheKeys.ROLE_DATA+"_all";
        List<SysRole> sysRoles = redisUtils.getCacheList(key);
        if(CollectionUtils.isNotEmpty(sysRoles)) return sysRoles;
        sysRoles = baseMapper.queryAll();
        if(CollectionUtils.isNotEmpty(sysRoles)) redisUtils.setCacheList(key,sysRoles);
        return sysRoles;
    }

    @Override
    public TablePageData<SysRole> queryList(PageQueryVo pageQueryVo, SysRole sysRole) {
        Page<SysRole> page = new Page<>(pageQueryVo.getCurrent(), pageQueryVo.getPageSize());
        IPage<SysRole> iPage = baseMapper.selectPage(page, buildWrapper(sysRole));
        if (iPage.getTotal() > 0) {
            for (SysRole record : iPage.getRecords()) {
                setPerems(record);
                setDeptIds(record);
            }
        }
        TablePageData<SysRole> sysRoleTablePageData = TablePageDataBuilderUtil.buildTablePageData(iPage);
        return sysRoleTablePageData;
    }

    @Override
    public Boolean checkNameUnique(SysRole sysRole) {
        if (StringUtils.isBlank(sysRole.getRoleName())) return true;
        return baseMapper.exists(Wrappers.lambdaQuery(SysRole.class)
                .ne(ObjectUtils.isNotEmpty(sysRole.getRoleId()), SysRole::getRoleId, sysRole.getRoleId())
                .eq(SysRole::getRoleName, sysRole.getRoleName()));
    }

    @Override
    public Boolean checkKeyUnique(SysRole sysRole) {
        if (StringUtils.isBlank(sysRole.getRoleKey())) return true;
        return baseMapper.exists(Wrappers.lambdaQuery(SysRole.class)
                .ne(ObjectUtils.isNotEmpty(sysRole.getRoleId()), SysRole::getRoleId, sysRole.getRoleId())
                .eq(SysRole::getRoleKey, sysRole.getRoleKey()));
    }


    private Wrapper<SysRole> buildWrapper(SysRole sysRole) {
        LambdaQueryWrapper<SysRole> wrapper = Wrappers.lambdaQuery(SysRole.class);
        wrapper.eq(StringUtils.isNoneBlank(sysRole.getRoleName()), SysRole::getRoleName, sysRole.getRoleName())
                .eq(StringUtils.isNoneBlank(sysRole.getRoleKey()), SysRole::getRoleKey, sysRole.getRoleKey())
                .orderByAsc(SysRole::getRoleSort);
        if (ObjectUtils.isNotEmpty(sysRole.getState())) wrapper.eq(SysRole::getState, sysRole.getState());
        else wrapper.eq(SysRole::getState, 0);
        return wrapper;
    }


    private void setPerems(SysRole sysRole){
        sysRole.setPerms(roleMenuService.queryMenuIdsByRoleId(sysRole.getRoleId()));
    }

    private void setDeptIds(SysRole sysRole){
        sysRole.setDeptIds(roleDeptService.queryDeptIdsByRoleId(sysRole.getRoleId()));
    }


}
